/**
 * 
 */
package se.ricardo.gamesorgs.client.controllers;

import javax.swing.JDialog;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import se.ricardo.gamesorgs.api.request.AddGameRequest;
import se.ricardo.gamesorgs.api.request.GamesOptionsRequest;
import se.ricardo.gamesorgs.client.modes.games.GamesEditDialog;
import se.ricardo.gamesorgs.client.modes.games.MainGamesPanel;
import se.ricardo.gamesorgs.database.models.GameContainer;
import se.ricardo.gamesorgs.database.models.GamesModel;


/**
 * Controller class for usage with the MVC design pattern.<br>
 * Handles GUI events which are caught by the listeners in this class.
 * Retrieves data from the model and gives it to the view.
 * <br>
 * 
 * @author Ricardo Ocaña Leal
 *
 */
public class GamesController {
	private MainGamesPanel gamesPanel;
	private GamesModel gamesModel;
	private GamesOptionsRequest request;
	
	/**
	 * Creates object to the view and the model.
	 * <br>
	 * 
	 * @param
	 * gui Object to the application frame, to display the view.
	 * */
	public GamesController() {		
		gamesModel = new GamesModel();
		gamesPanel = new MainGamesPanel();
		
		// update the view with the companies immediately
		gamesPanel.updateCompanies(gamesModel.getCompanies());
		gamesPanel.init();
		
		request = new GamesOptionsRequest();
		registerViewListeners();
		
		update();
	}
	
	/**
	 * Returns the {@link JPanel} with the contents for
	 * when the application is in "Games Mode".
	 * <br>
	 * 
	 * @return
	 * The Games view.*/
	protected JPanel getGamesView() {
		return gamesPanel;
	}
	
	/**
	 * Returns all available companies that are stored in the
	 * database.
	 * <br>
	 * 
	 * @return
	 * Object array with the companies.
	 * */
	protected Object[] getCompaniesArray() {
		return gamesModel.getCompanies().toArray();
		
	}
	
	/**
	 * Fills the edit/add game dialog with values corresponding to the
	 * currently selected ones in the "Games" view.
	 * <br>
	 * 
	 * @param
	 * d Object of the {@link JDialog}.
	 * */
	protected void fillCurrentDialogValues(GamesEditDialog d) {
		gamesPanel.updateOptionsRequest(request);
		d.fillForm(
				request,
				gamesModel.getSystems().keySet().toArray());
	}
	
	/**
	 * Fills the edit/add game dialog with the values corresponding
	 * to the currently selected game.
	 * <br>
	 * 
	 * @param
	 * d Reference to a {@link GamesEditDialog} object.
	 * */
	protected void fillSelectedGameValues(GamesEditDialog d) {
		GameContainer game = gamesPanel.getSelectedGame();
		gamesPanel.updateOptionsRequest(request);
		
		d.fillForm(game,
				request,
				gamesModel.getSystems().keySet().toArray());
	}
	
	/**
	 * Updates the edit/add game dialog with systems belonging to the
	 * selected company.
	 * <br>
	 * 
	 * @param
	 * d Reference to the {@link JDialog} object.
	 * */
	protected void updateDialogSystems(GamesEditDialog d) {
		int index = d.getCompanyIndex();
		String company = (String)getCompaniesArray()[index];
		
		d.updateSystems(gamesModel.getSpecificSystems(company), 0);
	}
	
	/**
	 * Sends a request to the "model" to add a new game to the database.
	 * <br>
	 * 
	 * @param
	 * addRequest Request with all necessary data for adding a new game.
	 * */
	protected void addGameToDatabase(AddGameRequest addRequest) {
		gamesModel.addGame(addRequest);
		
		// Force and prepare an update of the systems list.
		request.setSystemsUpdate(true);
		update();
	}
	
	/**
	 * Register the necessary listeners to handle user actions
	 * on the view and frame-
	 * */
	private void registerViewListeners() {
		gamesPanel.registerListeners(new OptionsChangedListener());
	}
	
	/**
	 * Called when the view needs to be updated with new data.
	 * */
	private void update() {
		gamesPanel.updateOptionsRequest(request);
		gamesModel.update(request);

		if(request.shouldSystemsUpdate()) {
			request.setSystemsUpdate(false);
			gamesPanel.updateSystems(
					gamesModel.getSystems(),
					request.getSystemsIndex()
					);
		}
		else {
			gamesPanel.updateGames(gamesModel.getGames());
		}
	}
	
	/**
	 * Called when the user has requested to shut down the
	 * application.<br>
	 * Run through several procedures.
	 * */
	protected void shutdownProcedure() {
		gamesModel.shutdown();
	}
	
	
	/**
	 * Listener that registers events from when the user
	 * changes the selected item in the side {@link JList}s
	 * or changes the state of the {@link JTabbedPane}.
	 * */
	public class OptionsChangedListener
		implements ListSelectionListener,
					ChangeListener {

		@Override
		public void valueChanged(ListSelectionEvent e) {
			
			// Only update if the mouse button has been released,
			// or when arrow up/down is pressed on the keyboard.
			if(!e.getValueIsAdjusting()) {
				update();
			}
		}

		@Override
		public void stateChanged(ChangeEvent e) {
			update();
		}
	}
}
